<?php
/**
*  @package :  class.main
*  @classID :   Request.class.php
*  @author  :  邝达峰
*  @date    : 2017-07-14
*  网站Request处理类
*/

class Request
{

	/**
	 * 需要判断的环境变量
	 */
	protected $_detectors = array(
	'get' => array('env' => 'REQUEST_METHOD', 'value' => 'GET'),
	'post' => array('env' => 'REQUEST_METHOD', 'value' => 'POST'),
	'put' => array('env' => 'REQUEST_METHOD', 'value' => 'PUT'),
	'patch' => array('env' => 'REQUEST_METHOD', 'value' => 'PATCH'),
	'delete' => array('env' => 'REQUEST_METHOD', 'value' => 'DELETE'),
	'head' => array('env' => 'REQUEST_METHOD', 'value' => 'HEAD'),
	'options' => array('env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'),
	'ssl' => array('env' => 'HTTPS', 'value' => 1),
	'ajax' => array('env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'),
	'flash' => array('env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'),
	'mobile' => array('env' => 'HTTP_USER_AGENT', 'options' => array(
	'Android', 'AvantGo', 'BlackBerry', 'DoCoMo', 'Fennec', 'iPod', 'iPhone', 'iPad',
	'J2ME', 'MIDP', 'NetFront', 'Nokia', 'Opera Mini', 'Opera Mobi', 'PalmOS', 'PalmSource',
	'portalmmm', 'Plucker', 'ReqwirelessWeb', 'SonyEricsson', 'Symbian', 'UP\\.Browser',
	'webOS', 'Windows CE', 'Windows Phone OS', 'Xiino'
	)),
	'requested' => array('param' => 'requested', 'value' => 1)
	);

	/**
	 * 系统环境变量
	 */
	protected $_environment = array();

	/**
    * 构造函数
    * @param:  NULL
    * @return: NULL
    * @access: public
    */
	public function __construct(){}

	/**
    * 析构函数
    * @param:  NULL
    * @return: NULL
    * @access: public
    */
	public function __destruct(){}


	/**
	 * 检查系统类型
	 * @param string $type 检查类型
	 * @return boolean
	 */
	public function checkEnv($type) {
		if (is_array($type)) {
			$result = array_map(array($this, 'is'), $type);
			return count(array_filter($result)) > 0;
		}
		$type = strtolower($type);
		if (!isset($this->_detectors[$type])) {
			return false;
		}
		$detect = $this->_detectors[$type];
		if (isset($detect['env'])) {
			if (isset($detect['value'])) {
				return $this->env($detect['env']) == $detect['value'];
			}
			if (isset($detect['pattern'])) {
				return (bool)preg_match($detect['pattern'], $this->env($detect['env']));
			}
			if (isset($detect['options'])) {
				$pattern = '/' . implode('|', $detect['options']) . '/i';
				return (bool)preg_match($pattern, $this->env($detect['env']));
			}
		}
		if (isset($detect['param'])) {
			$key = $detect['param'];
			if (isset($detect['value'])) {
				$value = $detect['value'];
				return isset($this->params[$key]) ? $this->params[$key] == $value : false;
			}
			if (isset($detect['options'])) {
				return isset($this->params[$key]) ? in_array($this->params[$key], $detect['options']) : false;
			}
		}
		if (isset($detect['callback']) && is_callable($detect['callback'])) {
			return call_user_func($detect['callback'], $this);
		}
		return false;
	}

	/**
	 * 获取/设置值从请求的环境数据。
	 * @param string $key 需要获取环境数据变量
	 * @param string $value 设置环境数据变量的值
	 * @return  null|string
	 */
	public function env($key, $value = null) {
		if ($value !== null) {
			$this->_environment[$key] = $value;
			return $this;
		}
		$key = strtoupper($key);
		if (!array_key_exists($key, $this->_environment)) {
			$this->_environment[$key] = $this->getEnvValue($key);
		}
		return $this->_environment[$key];
	}


	/**
	 * 获得一个环境变量
	 * @param string $key 环境变量的名字
	 * @return string 环境变量设置
	 */
	public function getEnvValue($key) {

		#判断请求协议环境变量类型
		if ($key === 'HTTPS') {
			if (isset($_SERVER['HTTPS'])) {
				return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
			}
			return (strpos($this->getEnvValue('SCRIPT_URI'), 'https://') === 0);
		}
		#判断CGI/SSI环境变量
		if ($key === 'SCRIPT_NAME') {
			if ($this->getEnvValue('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) {
				$key = 'SCRIPT_URL';
			}
		}
		#判断服务器环境变量
		$val = null;
		if (isset($_SERVER[$key])) {
			$val = $_SERVER[$key];
		} elseif (isset($_ENV[$key])) {
			$val = $_ENV[$key];
		} elseif (getenv($key) !== false) {
			$val = getenv($key);
		}
		#判断浏览当前页面的用户计算机的ip地址
		if ($key === 'REMOTE_ADDR' && $val === $this->getEnvValue('SERVER_ADDR')) {
			$addr = $this->getEnvValue('HTTP_PC_REMOTE_ADDR');
			if ($addr !== null) {
				$val = $addr;
			}
		}
		#判断是否匹配到值
		if ($val !== null) {
			return $val;
		}
		#判断其他环境变量
		switch ($key) {
			case 'DOCUMENT_ROOT'://根目录
			$name = $this->getEnvValue('SCRIPT_NAME');
			$filename = $this->getEnvValue('SCRIPT_FILENAME');
			$offset = 0;
			if (!strpos($name, '.php')) {
				$offset = 4;
			}
			return substr($filename, 0, -(strlen($name) + $offset));
			case 'PHP_SELF':
				return str_replace(env('DOCUMENT_ROOT'), '', $this->getEnvValue('SCRIPT_FILENAME'));
			case 'CGI_MODE':
				return (PHP_SAPI === 'cgi');
			case 'HTTP_BASE':
				$host = $this->getEnvValue('HTTP_HOST');
				$parts = explode('.', $host);
				$count = count($parts);

				if ($count === 1) {
					return '.' . $host;
				} elseif ($count === 2) {
					return '.' . $host;
				} elseif ($count === 3) {
					$gTLD = array(
					'aero',
					'asia',
					'biz',
					'cat',
					'com',
					'coop',
					'edu',
					'gov',
					'info',
					'int',
					'jobs',
					'mil',
					'mobi',
					'museum',
					'name',
					'net',
					'org',
					'pro',
					'tel',
					'travel',
					'xxx'
					);
					if (in_array($parts[1], $gTLD)) {
						return '.' . $host;
					}
				}
				array_shift($parts);
				return '.' . implode('.', $parts);
		}
		return null;
	}

	/**
	 * 获取请求的头信息。
	 * @param string $name
	 * @return array 头信息
	 */
	public function getHeader($name) {
		$name = 'HTTP_' . str_replace('-', '_', $name);
		return $this->env($name);
	}


	/**
	 * 获取HTTP_ACCEPT标题和内容类型
	 * @return array
	 */
	public function getAccept() {
		return $this->_parseAcceptWithQualifier($this->getHeader('accept'));
	}


	/**
	 * 解析接受头与限定符选项。
	 * @param string $header 头信息
	 * @return array
	 */
	protected function _parseAcceptWithQualifier($header) {
		$accept = array();
		$header = explode(',', $header);
		foreach (array_filter($header) as $value) {
			$prefValue = '1.0';
			$value = trim($value);

			$semiPos = strpos($value, ';');
			if ($semiPos !== false) {
				$params = explode(';', $value);
				$value = trim($params[0]);
				foreach ($params as $param) {
					$qPos = strpos($param, 'q=');
					if ($qPos !== false) {
						$prefValue = substr($param, $qPos + 2);
					}
				}
			}
			if (!isset($accept[$prefValue])) {
				$accept[$prefValue] = array();
			}
			if ($prefValue) {
				$accept[$prefValue][] = $value;
			}
		}
		krsort($accept);
		return $accept;
	}

	/**
      * 获取客户端使用的IP
      * @return string
    */
	public function getClientIp() {
		if ($this->env('HTTP_X_FORWARDED_FOR')) {
			$ipaddr = preg_replace('/(?:,.*)/', '', $this->env('HTTP_X_FORWARDED_FOR'));
		} else {
			if ($this->env('HTTP_CLIENT_IP')) {
				$ipaddr = $this->env('HTTP_CLIENT_IP');
			} else {
				$ipaddr = $this->env('REMOTE_ADDR');
			}
		}

		if ($this->env('HTTP_CLIENTADDRESS')) {
			$tmpipaddr = $this->env('HTTP_CLIENTADDRESS');

			if (!empty($tmpipaddr)) {
				$ipaddr = preg_replace('/(?:,.*)/', '', $tmpipaddr);
			}
		}
		return trim($ipaddr);
	}

	/**
      * 获取得到请求的主机
      * @return string
    */
	public function getHost() {
		if ($this->env('HTTP_X_FORWARDED_HOST')) {
			return $this->env('HTTP_X_FORWARDED_HOST');
		}
		return $this->env('HTTP_HOST');
	}


	/**
      * 获取得到请求的主机端口
      * @return string
    */
	public function getPort() {
		if ($this->env('HTTP_X_FORWARDED_PORT')) {
			return $this->env('HTTP_X_FORWARDED_PORT');
		}
		return $this->env('SERVER_PORT');
	}

	/**
      * 获取当前的url请求方式
      * @return string
    */
	public function getHttp() {
		if ($this->env('HTTP_X_FORWARDED_PROTO')) {
			return $this->env('HTTP_X_FORWARDED_PROTO');
		}
		return $this->env('HTTPS') ? 'https' : 'http';
	}

	/**
      * 获取到根域名
      * @return string
    */
	public function getDomain($tldLength = 1) {
		$segments = explode('.', $this->getHost());
		$domain = array_slice($segments, -1 * ($tldLength + 1));
		return implode('.', $domain);
	}


	/**
      * 获取语言被客户接受语言
      * @param $language 需要获取到的语言
      * @return string
    */
	public function getAcceptLang($language = null) {
		$raw = $this->_parseAcceptWithQualifier($this->getHeader('Accept-Language'));
		$accept = array();
		foreach ($raw as $languages) {
			foreach ($languages as &$lang) {
				if (strpos($lang, '_')) {
					$lang = str_replace('_', '-', $lang);
				}
				$lang = strtolower($lang);
			}
			$accept = array_merge($accept, $languages);
		}
		if ($language === null) {
			return $accept;
		}
		return in_array(strtolower($language), $accept);
	}



}
?>